﻿using System;
using System.Collections.Generic;
using Krile.Kernel;
using Krile.Kernel.WindowsEx;

namespace Twinkle
{
    public static class TwitterCommonOperation
    {
        public static IEnumerable<Data.Account> EnumeratePostableAccounts()
        {
            if (Kernel.Config.Accounts == null)
                yield break;
            foreach (var a in Kernel.Config.Accounts)
            {
                if ((a.UsingState & Twinkle.Data.Account.UsingStates.Update) == Twinkle.Data.Account.UsingStates.Update)
                    yield return a;
            }
        }

        public static IEnumerable<Data.Account> EnumerateReceivableAccounts()
        {
            if (Kernel.Config.Accounts == null)
                yield break;
            foreach (var a in Kernel.Config.Accounts)
            {
                if ((a.UsingState & Twinkle.Data.Account.UsingStates.Receive) == Twinkle.Data.Account.UsingStates.Receive)
                    yield return a;
            }
        }

        public static IEnumerable<Data.Account> EnumerateOperatableAccounts()
        {
            if (Kernel.Config.Accounts == null)
                yield break;
            foreach (var a in Kernel.Config.Accounts)
            {
                if ((a.UsingState & Twinkle.Data.Account.UsingStates.Operate) == Twinkle.Data.Account.UsingStates.Operate)
                    yield return a;
            }
        }

        public static OperationResult<object> Update(string text, ulong replyto, object affixObject)
        {
            bool treatAsDM = false;
            string dmRecipientId = null;
            string dmText = null;
            if (Kernel.Config.External.URLShoteningService.Use &&
                !Kernel.Config.External.URLShoteningService.UseOnlyExceeds ||
                (Kernel.Config.External.URLShoteningService.UseOnlyExceeds && text.Length > 140)
                )
            {
                var rgx = Krile.Common.Regexs.URLRegex;
                text = rgx.Replace(text, (o) =>
                {
                    if (o.Captures.Count == 0 || URLShortener.URLShortenManager.IsCompressedThis(o.Value))
                        return o.Value;
                    var sug = URLShortener.URLShortenManager.GetSuggestedCompressor();
                    string nv;
                    if (sug.TryCompress(o.Value, out nv))
                        return nv;
                    else
                        return o.Value;
                });
            }

            var act = new Func<OperationResult<object>>(() =>
                {
                    if (text.Length > 3 && text.StartsWith("d @"))
                    {
                        dmText = text.Substring(3);
                        int splIdx = dmText.IndexOf(' ');
                        if (splIdx > 0)
                        {
                            //0でもアウト("d @ "みたいなテキストはinvalid)
                            dmRecipientId = dmText.Substring(0, splIdx);
                            if (splIdx == dmText.Length)
                                dmText = string.Empty;
                            else
                                dmText = dmText.Substring(splIdx + 1);
                            if (MessageBoxEx.Show(
                                Lang.Msg.TreatAsDm_Context, Lang.Msg.TreatAsDm,
                                Lang.Msg.TreatAsDm_Title, MessageBoxEx.MessageBoxExButtons.YesNo, MessageBoxEx.MessageBoxExIcon.Question)
                                 == MessageBoxEx.DialogResultEx.Yes)
                            {
                                treatAsDM = true;
                            }
                        }
                    }
                    if (Kernel.Config.Accounts.Length > 1 &&
                        Kernel.Config.Behavior.ConfirmAccountsBeforePost)
                    {
                        using (var f = new Dialogs.Account.AccountConfirmer(Dialogs.Account.AccountConfirmer.LinkType.Post))
                        {
                            Bridge.MainForm.AppendChild(f);
                            if (f.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                                return new OperationResult<object>() { Succeeded = false, Message = "Cancelled" };
                        }
                    }
                    return null;
                });

            var r = Bridge.MainForm.SafeOperate(act) as OperationResult<object>;
            if (r != null)
                return r;

            //update status
            OperationResult<object> retobj = new OperationResult<object>() { Succeeded = true };
            foreach (var a in EnumeratePostableAccounts())
            {
                try
                {
                    var ctext = text;
                    if (treatAsDM)
                    {
                        //remove "d "
                        var obj = a.SendDirectMessage(dmText, dmRecipientId);
                        if (obj == null || !obj.Succeeded)
                            retobj = obj;
                    }
                    else
                    {
                        if (!Kernel.Config.Behavior.DontUseSignatureWhenContainsRT ||
                            (!ctext.Contains("RT") && !ctext.Contains("QT")))
                            if (!Kernel.Config.Behavior.DontUseSignatureWhenContainsReply ||
                                !Krile.Common.Regexs.AtRegex.IsMatch(ctext))
                                if (a.UseSignature)
                                    ctext += a.Signature;
                        //署名で文字数をオーバーした時も短縮する
                        if (Kernel.Config.External.URLShoteningService.Use &&
                            Kernel.Config.External.URLShoteningService.UseOnlyExceeds &&
                            ctext.Length > 140)
                        {
                            var rgx = Krile.Common.Regexs.URLRegex;
                            ctext = rgx.Replace(ctext, (o) =>
                            {
                                if (o.Captures.Count == 0 || URLShortener.URLShortenManager.IsCompressedThis(o.Value))
                                    return o.Value;
                                var sug = URLShortener.URLShortenManager.GetSuggestedCompressor();
                                string nv;
                                if (sug.TryCompress(o.Value, out nv))
                                    return nv;
                                else
                                    return o.Value;
                            });
                        }
                        var obj = a.Update(ctext, Kernel.Storage.GetSid(replyto));
                        if (obj == null || !obj.Succeeded)
                            retobj = obj;
                    }
                }
                catch (Exception e)
                {
                    retobj = new OperationResult<object>() { Exception = e, Succeeded = false, Message = e.Message };
                }
            }
            return retobj;
        }

        public static OperationResult<object> SetFavorite(ulong uid, bool create)
        {
            var sid = Kernel.Storage.GetSid(uid);
            if (sid == null)
                throw new ArgumentException("uid is invalid.");
            OperationResult<object> or = new OperationResult<object>() { Succeeded = true };
            var act = new Func<OperationResult<object>>(() =>
                {
                    if (Kernel.Config.Accounts.Length > 1 &&
                        Kernel.Config.Behavior.ConfirmAccountsBeforeFav)
                        using (var f = new Dialogs.Account.AccountConfirmer(Dialogs.Account.AccountConfirmer.LinkType.Fav))
                        {
                            Bridge.MainForm.AppendChild(f);
                            if (f.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                                return new OperationResult<object>() { Succeeded = false, Message = "Cancelled" };
                        }
                    return null;
                });
            var r = Bridge.MainForm.SafeOperate(act) as OperationResult<object>;
            if (r != null)
                return r;
            foreach (var s in EnumerateOperatableAccounts())
            {
                try
                {
                    var re = s.SetFavorite(sid, create);
                    if (re == null || !re.Succeeded)
                        or = re;
                }
                catch (Exception e)
                {
                    or = new OperationResult<object>() { Exception = e, Message = e.Message, Succeeded = false };
                }
            }
            return or;
        }

        public static OperationResult<object> Retweet(ulong uid)
        {
            var sid = Kernel.Storage.GetSid(uid);
            if (sid == null)
                throw new ArgumentException("uid is invalid.");
            if (!Bridge.StatusManager.IdExists(uid))
                throw new ArgumentException("status is not existed.");
            var s = Bridge.StatusManager.GetStatus(uid) as Tweak.TStatus;
            if (s == null || s.User == null)
                throw new ArgumentException("status is invalid.");
            if (s.User.Protected)
                throw new ArgumentException("this status is protected.");
            OperationResult<object> or = new OperationResult<object>() { Succeeded = true };
            var act = new Func<OperationResult<object>>(() =>
            {
                if (Kernel.Config.Accounts.Length > 1 &&
                    Kernel.Config.Behavior.ConfirmAccountsBeforePost)
                {
                    using (var f = new Dialogs.Account.AccountConfirmer(Dialogs.Account.AccountConfirmer.LinkType.RT))
                    {
                        Bridge.MainForm.AppendChild(f);
                        if (f.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
                            return new OperationResult<object>() { Succeeded = false, Message = "Cancelled" };
                    }
                }
                return null;
            });
            var sor = Bridge.MainForm.SafeOperate(act) as OperationResult<object>;
            if (sor != null)
                return sor;

            foreach (var a in EnumerateOperatableAccounts())
            {
                try
                {
                    var r = a.Retweet(sid);
                    if (r == null || !r.Succeeded)
                        or = r;
                }
                catch (Exception e)
                {
                    or = new OperationResult<object>() { Exception = e, Message = e.Message, Succeeded = false };
                }
            }
            return or;
        }

        public static void UnofficialRetweet(string target_id, string target_text)
        {
            Bridge.MainForm.InputControlManager.SetServices(new[] { Kernel.Plugin.TOperation.HostingService }, false);
            Bridge.MainForm.InputControlManager.SetInputText(" RT @" + target_id + ": " + target_text);
        }

        public static void Quote(string id, string target_id, string target_text)
        {
            Bridge.MainForm.InputControlManager.SetReplyTo(Kernel.Storage.GetUid(id));
            Bridge.MainForm.InputControlManager.SetInputText(" QT @" + target_id + ": " + target_text);
        }
    }
}
